package com.cskaoyan;

import com.cskaoyan.utils.JDBCUtils;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;

/**
 * 创建日期: 2022/04/25 20:05
 *
 * @author ciggar
 *
 * 自定义的数据库连接池，主要实现了以下功能
 *
 * 1. 获取连接
 *
 * 2. close方法释放连接
 *
 * 3. 实现Datasource接口
 *
 * 4. 装饰器模式，增强JDBC4Connection
 *
 * 5. 自动扩容
 *
 * 6. 扩容上限
 *
 * 7. 获取连接保证线程安全
 *
 * 8. 数据库连接池可配置，也可使用默认配置
 *
 * 9. 超时自动回收
 *
 */
public class MyConnectionPool  implements DataSource {

    // 初始化容量
    static int INIT_SIZE = 5;

    // 最小值
    static int MIN_SIZE = 2;

    // 扩容增量
    static int INCREMENT_SIZE = 5;

    // 计数，记录线程池内线程总数
    static int count = 0;

    // 线程池内最大值
    static int MAX_SIZE = 50;

    // 回收连接阈值
    static int RETURN_SIZE = 10;

    // 回收大小
    static int RESET_SIZE = 8;



    /**
     * 创建日期：2022/04/25 20:45
     * @return java.sql.Connection
     * @author ciggar
     *
     * 只关注获取连接的方法和返回连接的方法
     */

    // 从头部存，从尾部取
    static LinkedList<Connection> connectionList;

    static {
        // 获取配置中的值
        try {
            FileInputStream fileInputStream = new FileInputStream("myconnectionpool.properties");
            Properties properties = new Properties();
            properties.load(fileInputStream);

            if (properties.getProperty("init_size") != null || properties.getProperty("init_size").length() > 0) {
                INIT_SIZE = Integer.valueOf(properties.getProperty("init_size"));
            }
            if (properties.getProperty("min_size") != null || properties.getProperty("min_size").length() > 0) {
                MIN_SIZE = Integer.valueOf(properties.getProperty("min_size"));
            }
            if (properties.getProperty("increment_size") != null || properties.getProperty("increment_size").length() > 0) {
                INCREMENT_SIZE = Integer.valueOf(properties.getProperty("increment_size"));
            }
            if (properties.getProperty("max_size") != null || properties.getProperty("max_size").length() > 0) {
                MAX_SIZE = Integer.valueOf(properties.getProperty("max_size"));
            }
            if (properties.getProperty("return_size") != null || properties.getProperty("return_size").length() > 0) {
                RETURN_SIZE = Integer.valueOf(properties.getProperty("return_size"));
            }
            if (properties.getProperty("reset_size") != null || properties.getProperty("reset_size").length() > 0) {
                RESET_SIZE = Integer.valueOf(properties.getProperty("reset_size"));
            }


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


        // 初始化
        connectionList = new LinkedList<>();

        // 扩容
        addCapcity(INIT_SIZE);


        // 设置计时器，触发回收方法
        // 30秒之后开始执行，每30s执行一次
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                release();
            }
        },1000*30,1000*30);



    }



    // 扩容
    private synchronized static void addCapcity(int capCity) {

        System.out.println("add addCapcity start ... capCity:" +capCity);

        // 如果扩容的总数量大于设定的最大值
        if (count >  MAX_SIZE) {
            return;
        }

        for (int i = 0; i < capCity; i++) {
            Connection connection = JDBCUtils.getConnection();
            MyConnection myConnection = new MyConnection(connectionList,connection);
            connectionList.addFirst(myConnection);

            count++;
        }
    }


    // 获取连接
    @Override
    public synchronized  Connection getConnection() throws SQLException {


        // 判断，如果小于设定最小值，就自动扩容
        if (connectionList.size() < MIN_SIZE) {
            addCapcity(INCREMENT_SIZE);
        }


        if (connectionList.size() < 1){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            Connection connection = connectionList.removeLast();
            System.out.println("连接池中还有：" + connectionList.size() + " 个连接");
            return connection;
        }

        // 再次获取
        Connection connection = getConnection();

        return connection;
    }


    // 返回连接
    public static void returnConnection(Connection connection){
        connectionList.addFirst(connection);
    }


    // 回收连接
    public static void release(){

        int m = 0;

        System.out.println("releaseConnection start...");
        if (connectionList.size()> RETURN_SIZE) {

            for (int i = 0; i < connectionList.size() - RESET_SIZE; i++) {
                MyConnection connection = (MyConnection) connectionList.removeLast();
                connection.realClose();
                m ++;
                count --;
            }
        }

        System.out.println("release：" + m + " connection ...");
        System.out.println("releaseConnection end ...");
    }


    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}
